//
// Created by Administrator on 2021/10/21.
//

#include "Object3D.h"

static int ct = 0;

Object3D::Object3D() {
    id = ++ct;
    uuid = String::toString("%p", this);
    type = GET_CLASS(__FILE__);
    name = type + "_" + id;

    bTickable = true;
    bVisible = true;

    // location param
    location.x = 0.0f;
    location.y = 0.0f;
    location.z = 0.0f;
    up.x = 0.0f;
    up.y = 1.0f;
    up.z = 0.0f;
    rotation.x = 0.0f;
    rotation.y = 0.0f;
    rotation.z = 0.0f;
    scale.x = 1.0f;
    scale.y = 1.0f;
    scale.z = 1.0f;

    this->p_material = NULL;
}

/**
 * 析构
 */
Object3D::~Object3D() {
    log_info("gc Object3D! %p", this);
    if(!geometries.empty()) {
        for (auto iterator = geometries.begin(); iterator != geometries.end(); iterator ++) {
            if (NULL != *iterator) {
                SAFE_DELETE(*iterator);
            }
        }
        std::vector<BufferGeometry *>().swap(geometries);
    }

    SAFE_DELETE(p_material);
}

/**
 * 应用材质
 * @param p_aterial
 */
void Object3D::applyMaterial(Material *p_material) {
    SAFE_DELETE(this->p_material)
    this->p_material = p_material;
}

/**
 * 初始化
 */
void Object3D::onInit() {
    log_info("object onInit. %p", this);
    // todo 这个步骤是否引起额外开销，仍需考虑
//    if(!geometries.empty()) {
//        for (auto iterator = geometries.begin(); iterator != geometries.end(); iterator ++) {
//            if (NULL != *iterator) {
//                SAFE_DELETE(*iterator);
//            }
//        }
//        std::vector<BufferGeometry *>().swap(geometries);
//    }
//
//    SAFE_DELETE(p_material);

    p_material = new Material();

    for (auto it = geometries.begin(); it != geometries.end(); ++it) {
        BufferGeometry *geometry = *it;
        if(geometry){
            geometry->applyMaterial(p_material);
            geometry->onInit();
        }
    }
}

/**
 * 绘制
 * @param elapsedTime 时间
 * @param proj 投影矩阵
 * @param view 试图矩阵
 * @param pworld 世界矩阵
 */
void Object3D::onRender(float elapsedTime, Matrix4x4 proj, Matrix4x4 view, Matrix4x4 pworld) {
    if(!bVisible) return;
    for (auto it = geometries.begin(); it != geometries.end(); ++it) {
        BufferGeometry *geometry = *it;
        if(geometry){
            geometry->onRender(elapsedTime, proj, view, pworld * getModelmatrix());
        }
    }
}

/**
 * 物体应用矩阵
 * @param matrix 矩阵
 */
void Object3D::applyMatrix(Matrix4x4 matrix){
    this->toApplyMatrix = matrix;
}

/**
 * 返回模型矩阵
 * @return 矩阵
 */
Matrix4x4 Object3D::getModelmatrix() {
    Matrix4x4 transform;
    //scale
    transform = Matrix4x4::scale(transform, scale);
    //rotator
    Matrix4x4 rm = getRotationMatrix();
    transform = transform * rm;
    //translate
    transform = Matrix4x4::translation(transform, location);

    return transform * toApplyMatrix;
}

/**
 * 计算旋转矩阵
 * @return todo 因为这里后期要加 四元素旋转，所以单独抽个方法
 */
Matrix4x4 Object3D::getRotationMatrix() {
    Matrix4x4 rm;
    rm = Matrix4x4::rotation(rm, Angle::deg2rad(rotation.x), Vector3(1, 0, 0));
    rm = Matrix4x4::rotation(rm, Angle::deg2rad(rotation.y), Vector3(0, 1, 0));
    rm = Matrix4x4::rotation(rm, Angle::deg2rad(rotation.z), Vector3(0, 0, 1));
    return rm;
}

/**
 * 显示UI
 */
void Object3D::getUI() {
    // info
    ImGui::Text("Type:");
    ImGui::SameLine();
    ImGui::Text("%s", this->type.c_str());
    ImGui::Text("Id:");
    ImGui::SameLine();
    ImGui::Text("%d", this->id);
    ImGui::Text("UUID:");
    ImGui::SameLine();
    ImGui::Text("%s", this->uuid.c_str());
    ImGui::InputText("Name", this->name.toC_str(), 128);
    ImGui::Checkbox("Visible", &this->bVisible);

    // transform
    ImGui::Text("Transform:");
    ImGui::DragFloat3("Location", &this->location.x, 0.01f, -1000.0f, 1000.0f);
    ImGui::DragFloat3("Rotation", &this->rotation.x, 1.0f, -360.0f, 360.0f);
    ImGui::DragFloat3("Scale", &this->scale.x, 0.01f, -5.0f, 5.0f);

    ImGui::Text("Geometry：");
    for (auto it = geometries.begin(); it != geometries.end(); ++it) {
        BufferGeometry *geometry = *it;
        if(geometry){
            geometry->getUI();
        }
    }

    static Matrix4x4 _matrix;
    ImGui::Text("ApplyMatrix 4X4:");
    if(ImGui::InputFloat4("row1", &_matrix.data[0])){
        applyMatrix(_matrix);
    }
    if(ImGui::InputFloat4("row2", &_matrix.data[4])){
        applyMatrix(_matrix);
    }
    if(ImGui::InputFloat4("row3", &_matrix.data[8])){
        applyMatrix(_matrix);
    }
    if(ImGui::InputFloat4("row4", &_matrix.data[12])){
        applyMatrix(_matrix);
    }
}









